aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes/[username]
diff options
context:
space:
mode:
authorAdrien Hopkins <[email protected]>2022-08-02 13:13:27 -0500
committerAdrien Hopkins <[email protected]>2022-08-02 13:13:27 -0500
commitc21ee41b206db79b2157d8743b0473a094448dfb (patch)
treefac1a595e451c0b32ceedfe4fb70855270456377 /src/routes/[username]
parent3b216dd6c170a7d71d21a391098c554008c8bdb4 (diff)
parent05f5001fc7d325e31d9c777be11343604c72fbfd (diff)
downloadcoinos-ui-c21ee41b206db79b2157d8743b0473a094448dfb.tar.gz
coinos-ui-c21ee41b206db79b2157d8743b0473a094448dfb.zip
Merge branch 'master' into i18n
Diffstat (limited to 'src/routes/[username]')
-rw-r--r--src/routes/[username]/customers.svelte5
-rw-r--r--src/routes/[username]/dashboard.svelte5
-rw-r--r--src/routes/[username]/index.js14
-rw-r--r--src/routes/[username]/index.svelte95
-rw-r--r--src/routes/[username]/receive.svelte187
-rw-r--r--src/routes/[username]/settings.svelte5
-rw-r--r--src/routes/[username]/transactions.svelte5
7 files changed, 316 insertions, 0 deletions
diff --git a/src/routes/[username]/customers.svelte b/src/routes/[username]/customers.svelte
new file mode 100644
index 00000000..1935b156
--- /dev/null
+++ b/src/routes/[username]/customers.svelte
@@ -0,0 +1,5 @@
+<script>
+ import { AppHeader } from '$comp';
+</script>
+
+<AppHeader />
diff --git a/src/routes/[username]/dashboard.svelte b/src/routes/[username]/dashboard.svelte
new file mode 100644
index 00000000..1935b156
--- /dev/null
+++ b/src/routes/[username]/dashboard.svelte
@@ -0,0 +1,5 @@
+<script>
+ import { AppHeader } from '$comp';
+</script>
+
+<AppHeader />
diff --git a/src/routes/[username]/index.js b/src/routes/[username]/index.js
new file mode 100644
index 00000000..5de1316f
--- /dev/null
+++ b/src/routes/[username]/index.js
@@ -0,0 +1,14 @@
+import { get } from '$lib/utils';
+
+export async function GET({ params }) {
+ let { username } = params;
+ let body;
+
+ try {
+ body = await get(`/users/${username}`);
+ } catch (e) {
+ body = {};
+ }
+
+ return { body };
+}
diff --git a/src/routes/[username]/index.svelte b/src/routes/[username]/index.svelte
new file mode 100644
index 00000000..6002efdc
--- /dev/null
+++ b/src/routes/[username]/index.svelte
@@ -0,0 +1,95 @@
+<script>
+ import { toast } from '@zerodevx/svelte-toast';
+ import { browser } from '$app/env';
+ import { onMount } from 'svelte';
+ import { AppHeader, Icon, PageNotFound } from '$comp';
+ import { user } from '$lib/store';
+ import { copy } from '$lib/utils';
+ export let username;
+
+ let lightningAddress = `${username}@coinos.io`;
+
+ onMount(async () => {
+ if (browser) {
+ let { default: QRCodeStyling } = await import('qr-code-styling');
+ const qrCode = new QRCodeStyling({
+ width: window.screen.width < 640 ? 250 : 300,
+ type: 'svg',
+ data: 'add static qr here',
+ image: '/images/invoice.svg',
+ backgroundOptions: {
+ color: 'rgba(0, 0, 0, 0)'
+ },
+ dotsOptions: {
+ type: 'rounded'
+ },
+ imageOptions: {
+ hideBackgroundDots: false
+ }
+ });
+
+ qrCode.append(document.getElementById('qr'));
+ }
+ });
+
+ let followed = false;
+
+ let qrSkeleton = true;
+ setTimeout(() => (qrSkeleton = false), 100);
+
+ const handleCopy = () => {
+ copy(lightningAddress);
+ toast.push('Copied!', {
+ theme: {
+ '--toastBarBackground': '#2F855A'
+ }
+ });
+ };
+</script>
+
+{#if username}
+ <AppHeader avatarPosition="left-[calc(15vw-48px)]" />
+
+ <div class="flex xl:block justify-center items-center my-20 px-3">
+ <div class="space-y-10 xl:space-y-0">
+ <div class="xl:ml-[calc(15vw-48px)] space-y-2 w-full md:w-72">
+ <h1 class="text-3xl font-bold">{username}</h1>
+
+ <p class="text-secondary">Address goes here</p>
+
+ <button
+ class="border rounded-full py-2 w-28 font-semibold flex justify-center items-center text-sm"
+ on:click={() => (followed = !followed)}
+ ><Icon icon={followed ? 'minus' : 'plus'} style="mr-1" />
+ {followed ? 'Remove' : 'Follow'}
+ </button>
+ </div>
+
+ <div class="space-y-5 static xl:absolute top-[255px] left-[calc(50vw-150px)]">
+ <div
+ id="qr"
+ class="border border-lightgrey rounded-3xl flex md:p-5 justify-center items-center relative"
+ >
+ <div
+ class="z-100 h-[300px] md:h-[342px] w-[250px] md:w-[342px] animate-pulse absolute top-0 left-0 bg-gray-400 rounded-3xl {qrSkeleton
+ ? 'block'
+ : 'hidden'}"
+ />
+ </div>
+
+ <p class="text-secondary text-center font-semibold">Scan to pay with Bitcoin</p>
+
+ <div
+ class="bg-primary font-semibold rounded-xl text-sm py-2 px-3 flex flex-wrap justify-center items-center"
+ >
+ <span>{lightningAddress}</span>
+ <button on:click={handleCopy}>
+ <Icon icon="copy" style="ml-2" />
+ </button>
+ </div>
+ </div>
+ </div>
+ </div>
+{:else}
+ <PageNotFound />
+{/if}
diff --git a/src/routes/[username]/receive.svelte b/src/routes/[username]/receive.svelte
new file mode 100644
index 00000000..50fddbed
--- /dev/null
+++ b/src/routes/[username]/receive.svelte
@@ -0,0 +1,187 @@
+<script>
+ // in the future we will want to allow users to set their fiat currency in the settings
+ import { AppHeader, Icon } from '$comp';
+ import { goto } from '$app/navigation';
+ import { invoiceAmount, invoiceAmountFiat, rate, user } from '$lib/store';
+ import { post } from '$lib/utils';
+ import { page } from '$app/stores';
+
+ let useFiat = true;
+ let amountFiat = 0;
+ let amountSats = 0;
+ let message = '';
+
+ $: amount = useFiat ? Math.round(amountFiat / ($rate / 100000000)) : amountSats;
+
+ $: $invoiceAmount = parseInt(amountSats === 0 ? amountFiat / ($rate / 100000000) : amountSats);
+ $: $invoiceAmountFiat = parseInt(
+ amountFiat === 0 ? amountSats * ($rate / 100000000) : amountFiat
+ );
+ $: amountSatsFormatted = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format(
+ amountSats
+ );
+
+ $: amountFiatConverted = new Intl.NumberFormat('en-US', {
+ style: 'currency',
+ currency: 'USD'
+ }).format(amountSats * ($rate / 100000000));
+
+ $: amountSatsConverted = new Intl.NumberFormat('en-US', { maximumFractionDigits: 0 }).format(
+ amountFiat / ($rate / 100000000)
+ );
+
+ const numPad = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '0', '<'];
+
+ const handleInput = (value) => {
+ if (message) {
+ message = '';
+ }
+ if (useFiat) {
+ if (amountFiat === 0 && value !== '.' && value !== '<' && value !== '0') {
+ amountFiat = value;
+ } else if ((amountFiat === 0 || amountFiat === '0') && value === '0') {
+ return;
+ } else if (amountFiat === 0 && value === '.') {
+ amountFiat = '0.';
+ } else if (amountFiat !== 0 && amountFiat.includes('.') && value === '.') {
+ return;
+ } else if (value === '<') {
+ if (amountFiat !== 0) {
+ amountFiat = amountFiat.slice(0, amountFiat.length - 1);
+ if (amountFiat.length === 0) {
+ amountFiat = 0;
+ amountSats = 0;
+ }
+ }
+ } else if (value !== '.' && value !== '<' && parseInt(amountFiat + value) > $rate) {
+ message = 'Please enter an amount less than 1 bitcoin.';
+ } else if (amountFiat !== 0 && amountFiat.match(/\.../)) {
+ return;
+ } else {
+ amountFiat = amountFiat + value;
+ }
+ } else {
+ if (value === '.') {
+ return;
+ } else if (amountSats === 0 && value !== '<' && value !== '0') {
+ amountSats = value;
+ } else if (value === '<') {
+ if (amountSats !== 0) {
+ amountSats = amountSats.slice(0, amountSats.length - 1);
+ if (amountSats.length === 0) {
+ amountSats = 0;
+ amountFiat = 0;
+ }
+ }
+ } else if (value !== '<' && parseInt(amountSats + value) > 100000000) {
+ message = 'Please enter an amount less than 1 bitcoin.';
+ } else {
+ amountSats = amountSats + value;
+ }
+ }
+ };
+
+ let submit = async () => {
+ let { id } = await post('/invoice', { amount, rate: $rate, username: $page.params.username });
+ goto(`/invoice/${id}`);
+ };
+</script>
+
+{#if $user}
+ <AppHeader />
+
+ <div class="flex justify-center items-center mt-20 mb-3 px-3">
+ {#if $rate}
+ <div class="space-y-5">
+ <!-- amounts -->
+ <div class="text-center">
+ <div class="text-5xl md:text-6xl font-semibold tracking-widest mb-1">
+ {useFiat ? `$${amountFiat}` : amountSatsFormatted}<span
+ class="tracking-normal text-base font-normal">{useFiat ? 'USD' : 'SATS'}</span
+ >
+ </div>
+ <span class="text-secondary mr-1"
+ >{useFiat ? `${amountSatsConverted} SATS` : `${amountFiatConverted} USD`}</span
+ >
+ <button
+ on:click={() => {
+ if (useFiat) {
+ amountSats = (amountFiat / ($rate / 100000000)).toFixed(0).toString();
+ } else {
+ amountFiat =
+ (amountSats * ($rate / 100000000)).toFixed(2) > 0.0
+ ? (amountSats * ($rate / 100000000)).toFixed(2).toString()
+ : 0;
+ }
+ useFiat = !useFiat;
+ }}><Icon icon="swap" style="inline" /></button
+ >
+ </div>
+
+ <!-- error message -->
+ {#if message}
+ <div
+ class="text-orange-500 text-sm text-center font-bold bg-primary p-2 rounded-xl flex justify-center items-center space-x-1"
+ >
+ <Icon icon="info" style="w-5" />
+ <p>{message}</p>
+ </div>
+ {/if}
+
+ <!-- numpad -->
+ <div class="grid grid-cols-3 gap-2 w-full md:w-[300px] mx-auto">
+ {#each numPad as value}
+ {#if value === '<'}
+ <button
+ class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white flex justify-center items-center"
+ on:click={() => handleInput(value)}
+ >
+ <svg
+ class="w-5"
+ width="24"
+ height="24"
+ viewBox="0 0 24 24"
+ fill="none"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path
+ d="M15 19L8 12L15 5"
+ stroke="currentColor"
+ stroke-width="2"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ />
+ </svg>
+ </button>
+ {:else}
+ <button
+ class="bg-primary rounded-xl py-4 px-8 font-semibold active:bg-black active:text-white"
+ on:click={() => handleInput(value)}>{value}</button
+ >
+ {/if}
+ {/each}
+ </div>
+
+ <!-- buttons -->
+ <div class="space-y-3 w-full md:w-[300px] mx-auto">
+ <button
+ class="bg-black text-white rounded-xl w-full h-[48px] flex justify-center items-center font-semibold text-sm {$invoiceAmount ===
+ 0
+ ? 'opacity-50'
+ : 'opacity-100'}"
+ on:click={submit}
+ disabled={$invoiceAmount === 0}><Icon icon="qr" style="mr-2" /> Show QR</button
+ >
+ <button
+ class="bg-primary rounded-xl w-full h-[48px] flex justify-center items-center font-semibold text-sm"
+ disabled={true}><Icon icon="send" style="mr-2" /> Send Invoice</button
+ >
+ </div>
+ </div>
+ {:else}
+ <div
+ class="w-full md:w-[300px] h-[475px] md:h-[485px] animate-pulse bg-gray-400 rounded-xl"
+ />
+ {/if}
+ </div>
+{/if}
diff --git a/src/routes/[username]/settings.svelte b/src/routes/[username]/settings.svelte
new file mode 100644
index 00000000..1935b156
--- /dev/null
+++ b/src/routes/[username]/settings.svelte
@@ -0,0 +1,5 @@
+<script>
+ import { AppHeader } from '$comp';
+</script>
+
+<AppHeader />
diff --git a/src/routes/[username]/transactions.svelte b/src/routes/[username]/transactions.svelte
new file mode 100644
index 00000000..1935b156
--- /dev/null
+++ b/src/routes/[username]/transactions.svelte
@@ -0,0 +1,5 @@
+<script>
+ import { AppHeader } from '$comp';
+</script>
+
+<AppHeader />